<?php
/**
 * Bdat Site development
 * @author Will Skates
 */

/*----------------------------------------------------------------------------------------------------*/

/**
 * Outline of properties and functionality required to make and access user information within the system.
 * @author Will Skates
 */
require_once 'userprofile.php';
class User extends CI_Model {
	
	public $username;
	public $password;
	public $profile;
	public $ip = false;
	public $isbanned = false;
	public $id;
	public $role;
	
	public static $fields;
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Get all of the data about all users in the system.
	 * @return	Array	$users		- An array containing user objects for every user in the system.
	 */
	public function getAll()
	{
		
		$query = 'SELECT
							users.id,
							username,
							role,
							twitter,
							flickr,
							youtube,
							user_profiles.name as name,
							bio,
							gradyears.date as gradyear,
							feed,
							email,
							isguesttweeter
				  FROM		users
				  LEFT JOIN user_profiles ON userid = users.id
				  LEFT JOIN user_roles ON users.role = user_roles.uid
				  LEFT JOIN gradyears ON gradyears.uid = user_profiles.gradyear
		';
		
		$query	 	= $this->db->query($query);
		$result 	= $query->result();
		
		$len 		= sizeof($result);
		$i 			= 0;
		
		while ( $i < $len ) {
			
			$result[$i] = $this->makeWithInfo($result[$i]);
			
			$i++;
		}
		
		return $result;
		
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Check to see whether a use exists in the system with a certain unique identifier.
	 * @param	Integer		$id			- The unique identifier.
	 * @return	Boolean		$exists		- True/False as to whether the user exists.
	 */
	public function exists( $id )
	{
		$sql = 'SELECT id FROM users WHERE id = ' . $id;
		return (Boolean)sizeof($this->db->query($sql)->result());
		
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Check to see whether a user exists in the system with a specific username and password.
	 * @param	String		$username	- The username.
	 * @param	String		$password	- The password.
	 * @return	Boolean		$exists		- True/False as to whether the user exists.
	 */
	public function existsUP( $username, $password ) 
	{
		$sql = 'SELECT id FROM users WHERE username=\'' . $username . '\' AND password = \'' . md5($password) . '\'';
		return (Boolean)sizeof($this->db->query($sql)->result());
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Check to see whether a user exists in the system with a specific username.
	 * @param	String		$username	- The username.
	 * @return	Boolean		$exists		- True/False as to whether the user exists.
	 */
	public function existsU ( $username )
	{
		$sql = 'SELECT id FROM users WHERE username=\'' . $username . '\'';
		return (Boolean)sizeof($this->db->query($sql)->result());
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Check to see whether a user exists in the system where a certain field has a specific value.
	 * @param	String	$field	- The name of the field we want to search in.
	 * @param	String	$value	- The value that they want to use.
	 * @return	Boolean	$exists	- True/False as to whether the user exists.
	 */
	public function existsF( $field, $value ) 
	{
		if (in_array($field, array('email','twitter','youtube','flickr'))) {
			$table = 'user_profiles';
			$idf = 'uid';
		} else {
			$table = 'users';
			$idf = 'id';
		}
		$sql = 'SELECT ' . $idf . ' FROM ' . $table . ' WHERE ' . $field . '=?';
		return (Boolean)sizeof($this->db->query($sql,$value)->result());
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Does a user with a certain username have a certain level of access.
	 * @param	String	$username - The username.
	 * @param	Int		$level	  - The user level that we need to check against.
	 * @return	Boolean	$exists	  - True/False as to whether the user exists.
	 */
	public function hasAccess( $username, $level = 1 )
	{
		
		$sql = 'SELECT id,isbanned FROM users WHERE username =\'' . $username . '\' AND role >= ' . $level;
		$result = $this->db->query($sql)->result();
		
		if ( isset( $result[0]->isbanned ) && $result[0]->isbanned == true ) { return false; } 
		
		return (Boolean)sizeof($this->db->query($sql)->result());
		
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Check to see whether the user that belongs to this object has a certain level of access.
	 * @param	Int		$level		- The user level that we need to check against.
	 * @return	Boolean	$exists		- True/False as to whether the user exists.
	 */
	public function userHasAccess( $level = 1 )
	{
		if ( $this->banned() ) { return false; }
		return $this->canAccess($level);		
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Check to see whether the user that belongs to this object has a certain level of access.
	 * @param	Int		$level		- The user level that we need to check against.
	 * @return	Boolean	$exists		- True/False as to whether the user exists.
	 */
	public function canAccess( $level = 1 )
	{
		if ( $this->role >= $level ) {
			return true;
		}
		return false;
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Is this user currently banned?
	 * @return	Boolean	$banned		- True/False as to whether the user is banned.
	 */
	public function banned()
	{
		return (Boolean)$this->isbanned;
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Set the database table field information for all users according to the properties in this class.
	 */
	public function setFields()
	{
		if ( is_null(self::$fields) ) {
			self::$fields = array_keys((Array)$this);
		}
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Make a user object with provided user information
	 * @param	Array	$info	- Information from the users table.
	 * @return 	User	$user	- The user object.
	 */
	public function makeWithInfo( $info ) 
	{

		$this->setFields();
		$obj = new User();
		
		foreach ( $info as $k=>$v ) {
			
			if ( in_array( $k, self::$fields ) ) {
				$obj->$k = $v;
			}
			
		}
		
		$obj->profile = new UserProfile((Object)array_merge((Array)$info,array('userid'=>$obj->id)));
		
		return $obj;
		
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Make a user object from a provided unique identifier.
	 * @param	Array	$id		- The unique identifier.
	 * @return 	User	$user	- The user object.
	 */
	public function make( $id )
	{
		
		$query = 'SELECT
							users.id,
							username,
							ip,
							isbanned,
							role,
							twitter,
							flickr,
							youtube,
							user_profiles.name as name,
							bio,
							gradyears.date as gradyear,
							feed,
							isguesttweeter,
							email
				  FROM		users
				  LEFT JOIN user_profiles ON userid = users.id
				  LEFT JOIN user_roles ON users.role = user_roles.uid
				  LEFT JOIN gradyears ON gradyears.uid = user_profiles.gradyear
				  
				  WHERE users.id = ' . $id;
		
		$query	 	= $this->db->query($query);
		$result 	= $query->result();
		
		if ( sizeof($result) == 0 ) {
			return false;
		} 
		
		return $this->makeWithInfo($result[0]);
		
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Make a user object from a provided username and password.
	 * @param	String		$username	- The username.
	 * @param	String		$password	- The password.
	 * @return 	User		$user		- The user object.
	 */
	public function makeWithUsername( $username, $password = false ) 
	{
		
		$query = 'SELECT
							users.id,
							username,
							ip,
							isbanned,
							role,
							twitter,
							flickr,
							youtube,
							user_profiles.name as nickname,
							bio,
							gradyears.date as gradyear,
							feed,
							isguesttweeter,
							email
				  FROM		users
				  LEFT JOIN user_profiles ON userid = users.id
				  LEFT JOIN user_roles ON users.role = user_roles.uid
				  LEFT JOIN gradyears ON gradyears.uid = user_profiles.gradyear
				  
				  WHERE users.username=\'' . $username . '\'';
		
		if ( $password !== false ) { $query .= ' AND users.password=\'' . $password . '\''; }
		
		$query	 	= $this->db->query($query);
		$result 	= $query->result();
		
		if ( sizeof($result) == 0 ) {
			return false;
		} 
		
		return $this->makeWithInfo($result[0]);
		
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Get a user object for the currently logged in user.
	 * @return 	User		$user		- The user object.
	 */
	public function getLoggedInUser()
	{
		$this->load->Library('session');
		
		//If a session is running.
		if ($this->session->userdata('session_id') !== false) {
			
			//Get the username friom the session.
			$username = $this->session->userdata('username');
			
			//Make a user object.
			$user = $this->makeWithUsername($username);
			
			//Verify that the currently logged in user exists, if it doesn't kill the session.
			if($user === false) { $this->logOut(); return false;}
			
			return $user;
			
		}
		
		return false;
	}
	
	/*----------------------------------------------------------------------------------------------------*/

	/**
	 * Log a user in with a given username and password.
	 * @param	String		$username	- The username.
	 * @param	String		$password	- The password.
	 */
	public function logIn( $username, $password )
	{
		
		//Make a user object from a given username and password.
		$user = $this->makeWithUsername( $username, $password );
		
		//if the user exists then store their information in the session.
		if ( $user !== false ) {
			
			$this->load->Library('session');
			
			$newdata = array(
                   'username'  => $user->username,
                   'email'     => $user->profile->email,
                   'logged_in' => TRUE
               );

			$this->session->set_userdata($newdata);
			
			return true;
			
		}
		
		return false;
		
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Destroy the current session which logs out the current user.
	 * @return	Void.
	 */
	public function logOut()
	{
		$this->load->Library('session');
		$this->session->sess_destroy();
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Make a form through which people can enter their own profile information.
	 * @return		String		$html	- The html of the new form.
	 */
	public function makeDataForm()
	{
		
		//Load up all of the necessary classes that are equired to use zend form.
		$this->loadFormStuff();
		
		
		$this->form = new Zend_Form;
		$this->form->setAction('')->setMethod('post')->setEnctype(Zend_Form::ENCTYPE_MULTIPART);
		$this->form->setAttrib('id', 'loginF');
	
		$fields = array_merge((Array)$this, (Array)$this->profile);
		
		//Make sure we don't include any attributes that are moderated on the backend.
		unset($fields['username'],$fields['profile'],$fields['form'],$fields['isbanned'],$fields['ip'],$fields['password']);
		
		$elements = array();
		foreach ($fields as $k=>$field) {
			
			if ( 	
					$k != 'gradyear' 		&& 
					$k != 'bio' 			&& 
					$k != 'id' 				&& 
					$k != 'userid' 			&& 
					$k != 'isguesttweeter'  && 
					$k != 'role'
			) {
				$elements[$k] = new Zend_Form_Element_Text($k);
			} else if ( $k == 'bio' ) {
				$elements[$k] = new Zend_Form_Element_TextArea($k);
			} else if ( $k == 'id' ) {
				$elements[$k] = new Zend_Form_Element_Hidden($k);
			}
			
			if ( isset($elements[$k]) ) {
				
				if ( $k != 'id') { 
					
					//Set all fields to required and add some descriptive text for each element.
					$elements[$k]->setRequired(true); 
					$elements[$k]->setLabel(ucfirst(strtolower($k)) . ':');
				}
				
				//Set the value equal to the user's profile data.
				$elements[$k]->setValue($field);  
				
				//Add this element to the form.
				$this->form->addElement($elements[$k],$k);
				
			}	
		}
		
		//add a submit button.
		$elements['Submit'] = new Zend_Form_Element_Button('UserFrmSubmit');
		$elements['Submit']->setLabel('Submit' . ':');
		
		$this->form->addElement($elements['Submit'],'Submit');
		$this->form->populate($fields);
		
		$html = '';
		//Make sure that the user can be presented with the admin if they are logged in.
		if ( $this->userHasAccess(2) ) {
			$html = '<a href="/i-dat.org/admin/">Click here to view the admin panel</a>';
		} 
		
		$view = new Zend_View();
		
		return $html .= '<h3>User Name: ' . $this->username . '</h3>' . $this->form->render($view);
		
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Load up all of the necessary classes that are equired to use zend form.
	 * @return Void
	 */
	protected function loadFormStuff()
	{
		$this->load->library('zend','Zend/Form');
		$this->zend->load('Zend/Form');
		$this->zend->load('Zend/View');
		$this->zend->load('Zend/Form/Element/Text');
		$this->zend->load('Zend/Form/Element/Textarea');
		$this->zend->load('Zend/Form/Element/Hidden');
		$this->zend->load('Zend/Form/Element/Checkbox');
		$this->zend->load('Zend/Form/Element/Button');
		$this->zend->load('Zend/Form/Element/Submit');
	}
	
	/*----------------------------------------------------------------------------------------------------*/

	/**
	 * Update field values for this user from a given array.
	 * @param	Array	$info		-	The array of information we need to update.
	 * @return	Boolean	$success	- 	Whether the content was updated sucessfully.
	 */
	public function update($info)
	{
		
		$userFields = array_keys((Array)$this);
		$profileFields = array_keys((Array)$this->profile);
		
		$userData = array();
		$profileData = array();
		
		unset($userFields['profile']);
		
		//Check to make sure that the fields exist and content is only added into those fields.
		foreach ($info as $key=>$value) {
			if ( in_array($key,$userFields) ) {
				$userData[] = '`' . $key . '`=\'' . $value . '\'';
			} else if (in_array($key,$profileFields)) {
				$profileData[] = '`' . $key . '`=\'' . $value . '\'';
			}
		}
		
		$result = false;
		
		
		$userQuery = 'UPDATE users SET ' . implode(', ', $userData) . ' WHERE id=' . $this->id;
		$result = $this->db->query($userQuery);
		
		if ( count($profileData) ) {
			$profQuery = 'UPDATE user_profiles SET ' . implode(', ', $profileData) . ' WHERE userid=' . $this->id;
			$result = $this->db->query($profQuery);
		}
		
		return $result;
		
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Create a user database record using information inside arrays.
	 * @param	Array	$userInfo		-	The array of information we need to update regarding a user account.
	 * @param	Array	$profInfo		-	The array of information we need to update regarding a user's profile.
	 * @return	Boolean	$success		- 	Whether the content was updated sucessfully.
	 */
	public function create( $userInfo, $profInfo )
	{
		
		//Construct the fields and values.
		foreach($userInfo as $key=>$val) {
			$userInfo[$key] = '\'' . $val . '\'';
 		} 
 		
 		foreach($profInfo as $key=>$val) {
			$profInfo[$key] = '\'' . $val . '\'';
 		} 
		
		$userSQL = 'INSERT INTO users (' . implode(',', array_keys($userInfo)) . ') VALUES (' . implode(',',$userInfo) . ');';
		
		$result = $this->db->query($userSQL);
		
		$id = $this->db->insert_id();
		$profInfo['userid'] = $id;
		$userSQL = 'INSERT INTO user_profiles (' . implode(',',array_keys($profInfo)) . ') VALUES (' . implode(',',$profInfo) . ');';
		
		$result = $this->db->query($userSQL);
		
		return $result;
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Delete the database records for this user.
	 * @return	Void
	 */
	public function delete() 
	{
		$sql = 'DELETE FROM users WHERE id = ' . $this->id;
		$sql2 = 'DELETE FROM user_profiles WHERE userid = ' . $this->id;
		$this->db->query($sql);
		$this->db->query($sql2);
		unset($this);
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Create a user account from an email address.
	 * @param	String	$email	-	The email address that we want to use.
	 */
	public function createUser( $email )
	{
		
		$name = explode('.',reset(explode('@',$email)));
		
		//Make sure allparts of the users name are capitalized.
		foreach($name as $k=>$v) { $name[$k] = ucfirst($v); } 
		
		define('CHARS','abcdefghijklmnopqrstuvwxyz');
		define('CHARLEN',strlen(CHARS));
		$c = str_split(CHARS);
		
		$pass = (String)$c[mt_rand(0,CHARLEN)] . $c[mt_rand(0,CHARLEN)] . $c[mt_rand(0,CHARLEN)] . (String)(mt_rand(0,999) + (time() - 13 * 365 * 24 * 60 * 60));
		$uname = self::generateUsername($name[0]);
		
		$uInfo = array(
			'username'=>strtolower($uname),
			'password'=> md5($pass),
			'role'=>'0',
			'isbanned'=>'0',
			'ip'=>'',
			'session'=>''
		);
		
		$pInfo = array(
			'isguesttweeter'=>'0',
			'flickr'=>'',
			'youtube'=>'',
			'name'=>implode('',$name),
			'link'=>'',
			'bio'=>'',
			'gradyear'=>0,
			'feed'=>'',
			'email'=>$email
		);
		
		//Create the database records for the user.
		$success = $this->create($uInfo,$pInfo);
		
		//If the database records were created then send the user an email telling them about their new account.
		if ( $success ) {
			
			$this->load->library('email');

			$this->email->from('no-reply@b.i-dat.org', 'No Reply Bdat Site');
			$this->email->to($email);
			
			$this->email->subject('Registration Email.');
			$this->email->message(
				"
				Password notification
				Hello there " . $name[0] . ",
				You've been added to the Digital Art and Technology website at http://b.i-dat.org
							Your login details are:
							Username: " . strtolower($uname) .
							"Password: " . $pass
			);

	
		
	
			$this->email->send();
			
		}
		
	}
	
	/*----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Generate a new username for each user.
	 * @param	String	$name	- The username to begin with.
	 * @return 	String 	$name	- A new username.
	 */
	public function generateUsername($name)
	{
		
		if (!defined('CHARS')) {
			define('CHARS','abcdefghijklmnopqrstuvwxyz');
			define('CHARLEN',strlen(CHARS));
		}
		
		$c = str_split(CHARS);
	
		//Check to see whether a user exists in the system with that name.
		$sql = 'SELECT id FROM users WHERE username=?';
		$q = $this->db->query($sql, array($name) );
			
		//If it does...
		if ($q->num_rows() > 0) {
			
			//Then add some random characters to the end of it and check it again.
			$name .= $c[mt_rand(0,CHARLEN)] . mt_rand(0, 999);
			$name = $this->generateUsername($name);
			
		}
		
		return $name;
		
	}
	
	/*----------------------------------------------------------------------------------------------------*/
}